/*
 * Copyright (c) 2022 Hong Jiahua
 * https://gitee.com/arrco/jh_static_list
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#ifndef __JH_STATIC_LIST_H__
#define __JH_STATIC_LIST_H__

/************************************************************************/
/*                                                                      */
/************************************************************************/
//使用前需要支持这些类型

typedef unsigned char   uint8_t;
typedef unsigned short  uint16_t;
typedef unsigned int    uint32_t;
/************************************************************************/
/*                                                                      */
/************************************************************************/
//使用前需要设置以下参数

//存储空间有多大
#define JH_STATIC_LIST_BUF_VALID_LEN    62

//使用的数据类型
typedef uint32_t itemtype;

//使用的数据成员名称
#define JH_ITEM_NAME    data

/************************************************************************/
/*                                                                      */
/************************************************************************/
#define JH_STATIC_LIST_BUF_LEN      (JH_STATIC_LIST_BUF_VALID_LEN + 2)

//游标类型
#if JH_STATIC_LIST_BUF_LEN > 65536
#define JH_CURSOR_TYPE  uint32_t
#elif JH_STATIC_LIST_BUF_LEN > 256
#define JH_CURSOR_TYPE  uint16_t
#else
#define JH_CURSOR_TYPE  uint8_t
#endif

typedef struct
{
    itemtype        JH_ITEM_NAME;
    JH_CURSOR_TYPE  prev;
    JH_CURSOR_TYPE  next;
}jh_static_list_buf[JH_STATIC_LIST_BUF_LEN];
/************************************************************************/
/*                                                                      */
/************************************************************************/
#define JH_STATIC_LIST_END          (JH_STATIC_LIST_BUF_VALID_LEN + 1)
#define JH_STATIC_LIST_USE_HEAD     JH_STATIC_LIST_END
#define JH_STATIC_LIST_IDLE_HEAD    0
#define JH_STATIC_LIST_NULL         0

/**
 * 
 * @par Description:
 * 链表缓冲区初始化
 * 
 * @param list  链表
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_buf_init(jh_static_list_buf list)
{
    int i;
    
    for (i = 0; i < (JH_STATIC_LIST_BUF_LEN - 2); i++)
        list[i].next = i + 1;
    
    list[JH_STATIC_LIST_BUF_LEN - 2].next = JH_STATIC_LIST_NULL;
    
    list[JH_STATIC_LIST_USE_HEAD].next = JH_STATIC_LIST_USE_HEAD;
    list[JH_STATIC_LIST_USE_HEAD].prev = JH_STATIC_LIST_USE_HEAD;
}

/**
 * 
 * @par Description:
 * 链表初始化
 * 
 * @param list      链表
 * @param cursor    需要初始化的游标位置
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_init(jh_static_list_buf list, uint32_t cursor)
{
    list[cursor].next = cursor;
    list[cursor].prev = cursor;
}

/**
 * 
 * @par Description:
 * 申请链表游标
 * 
 * @param list      链表
 * 
 * @retval cursor.  游标位置
 * 
 */
static inline uint32_t jh_static_list_malloc(jh_static_list_buf list)
{
    uint32_t cursor = list[JH_STATIC_LIST_IDLE_HEAD].next;
    
    if(list[JH_STATIC_LIST_IDLE_HEAD].next)
        list[JH_STATIC_LIST_IDLE_HEAD].next = list[cursor].next;

    return cursor;
}

/**
 * 
 * @par Description:
 * 释放链表游标
 * 
 * @param list      链表
 * @param cursor    要进行释放的游标位置
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_free(jh_static_list_buf list, uint32_t cursor)
{
    list[cursor].next = list[JH_STATIC_LIST_IDLE_HEAD].next;
    list[JH_STATIC_LIST_IDLE_HEAD].next = cursor;
}

/**
 * 
 * @par Description:
 * 链表是否为空
 * 
 * @param list      链表
 * 
 * @retval TRUE  静态双向链表为空.
 * @retval FALSE 静态双向链表不为空.
 * 
 */
static inline uint32_t jh_static_list_is_empty(jh_static_list_buf list)
{
    return (list[JH_STATIC_LIST_USE_HEAD].next == JH_STATIC_LIST_USE_HEAD);
}

/**
 * 
 * @par Description:
 * 链表是否已满
 * 
 * @param list      链表
 * 
 * @retval TRUE  静态双向链表已满.
 * @retval FALSE 静态双向链表不为满.
 * 
 */
static inline uint32_t jh_static_list_is_full(jh_static_list_buf list)
{
    return (list[JH_STATIC_LIST_IDLE_HEAD].next == JH_STATIC_LIST_NULL);
}

/**
 * 
 * @par Description:
 * 向链表中添加结点
 * 
 * @param list      链表
 * @param target    要添加在哪个游标位置之后
 * @param cursor    所要添加的游标
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_add(jh_static_list_buf list, uint32_t target, uint32_t cursor)
{
    list[cursor].next = list[target].next;
    list[cursor].prev = target;
    
    list[(list[target].next)].prev = cursor;
    list[target].next = cursor;
}

/**
 * 
 * @par Description:
 * 向链表头添加结点
 * 
 * @param list      链表
 * @param cursor    所要添加的游标
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_head_insert(jh_static_list_buf list, uint32_t cursor)
{
    jh_static_list_add(list, JH_STATIC_LIST_USE_HEAD, cursor);
}

/**
 * 
 * @par Description:
 * 向链表尾添加结点
 * 
 * @param list      链表
 * @param cursor    所要添加的游标
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_tail_insert(jh_static_list_buf list, uint32_t cursor)
{
    jh_static_list_add(list, list[JH_STATIC_LIST_USE_HEAD].prev, cursor);
}

/**
 * 
 * @par Description:
 * 从链表中删除结点
 * 
 * @param list      链表
 * @param cursor    所要删除的游标
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_delete(jh_static_list_buf list, uint32_t cursor)
{
    list[(list[cursor].next)].prev = list[cursor].prev;
    list[(list[cursor].prev)].next = list[cursor].next;
    list[cursor].next = JH_STATIC_LIST_NULL;
    list[cursor].prev = JH_STATIC_LIST_NULL;
}

/**
 * 
 * @par Description:
 * 从链表中删除并释放结点
 * 
 * @param list      链表
 * @param cursor    所要删除并释放的游标
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_delete_and_free(jh_static_list_buf list, uint32_t cursor)
{
    jh_static_list_delete(list, cursor);
    jh_static_list_free(list, cursor);
}

/**
 * 
 * @par Description:
 * 从链表中删除并释放头结点
 * 
 * @attention
 * 未做保护，如果为空链表则会出错
 * 
 * @param list      链表
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_remove_head(jh_static_list_buf list)
{
    jh_static_list_delete_and_free(list, list[JH_STATIC_LIST_USE_HEAD].next);
}

/**
 * 
 * @par Description:
 * 从链表中删除并释放尾结点
 * 
 * @attention
 * 未做保护，如果为空链表则会出错
 * 
 * @param list      链表
 * 
 * @retval None.
 * 
 */
static inline void jh_static_list_remove_tail(jh_static_list_buf list)
{
    jh_static_list_delete_and_free(list, list[JH_STATIC_LIST_USE_HEAD].prev);
}

/**
 * 
 * @par Description:
 * 从链表中删除并返回头结点的游标
 * 
 * @param list      链表
 * 
 * @retval cursor   游标位置
 * 
 */
static inline uint32_t jh_static_list_get_and_remove_head_cursor(jh_static_list_buf list)
{
    uint32_t cursor = list[JH_STATIC_LIST_USE_HEAD].next;
    
    if(cursor == JH_STATIC_LIST_USE_HEAD)
        return 0;
    
    jh_static_list_delete(list, list[JH_STATIC_LIST_USE_HEAD].next);
    
    return cursor;
}

/**
 * 
 * @par Description:
 * 从链表中删除并返回尾结点的游标
 * 
 * @param list      链表
 * 
 * @retval cursor   游标位置
 * 
 */
static inline uint32_t jh_static_list_get_and_remove_tail_cursor(jh_static_list_buf list)
{
    uint32_t cursor = list[JH_STATIC_LIST_USE_HEAD].prev;
    
    if(cursor == JH_STATIC_LIST_USE_HEAD)
        return 0;
    
    jh_static_list_delete(list, list[JH_STATIC_LIST_USE_HEAD].prev);
    
    return cursor;
}

/**
 * 
 * @par Description:
 * 链表游标是否有效
 * 
 * @param cursor    游标
 * 
 * @retval TRUE     静态双向链表游标有效.
 * @retval FALSE    静态双向链表游标无效.
 * 
 */
static inline uint32_t jh_static_list_cursor_is_vaild(uint32_t cursor)
{
    return (cursor != JH_STATIC_LIST_NULL);
}

/**
 * 
 * @par Description:
 * 遍历链表
 * 
 * @param item  游标变量
 * @param list  链表
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH(item, list)         \
    for (item = list[JH_STATIC_LIST_USE_HEAD].next; \
         (item) != (JH_STATIC_LIST_USE_HEAD);       \
         item = list[item].next)

/**
 * 
 * @par Description:
 * 安全的遍历链表，可以在遍历中删除结点
 * 
 * @param item      游标变量
 * @param nextitem  游标变量
 * @param list      链表
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH_SAFE(item, nextitem, list)                      \
    for (item = list[JH_STATIC_LIST_USE_HEAD].next, nextitem = list[item].next; \
         (item) != (JH_STATIC_LIST_USE_HEAD);                                   \
         item = nextitem, nextitem = list[item].next)

/**
 * 
 * @par Description:
 * 反向遍历链表
 * 
 * @param item  游标变量
 * @param list  链表
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH_REVERSE(item, list) \
    for (item = list[JH_STATIC_LIST_USE_HEAD].prev; \
         (item) != (JH_STATIC_LIST_USE_HEAD);       \
         item = list[item].prev)

/**
 * 
 * @par Description:
 * 安全的反向遍历链表，可以在遍历中删除结点
 * 
 * @param item      游标变量
 * @param previtem  游标变量
 * @param list      链表
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH_SAFE_REVERSE(item, previtem, list)              \
    for (item = list[JH_STATIC_LIST_USE_HEAD].prev, previtem = list[item].prev; \
         (item) != (JH_STATIC_LIST_USE_HEAD);                                   \
         item = previtem, previtem = list[item].prev)

/**
 * 
 * @par Description:
 * 遍历链表获取数据
 * 
 * @param item      游标变量
 * @param list      链表
 * @param member    数据成员指针
 * @param element   数据成员名称
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT(item, list, member, element)          \
    for (item = list[JH_STATIC_LIST_USE_HEAD].next, member = &(list[item].element); \
         (item) != (JH_STATIC_LIST_USE_HEAD);                                       \
         item = list[item].next, member = &(list[item].element))

/**
 * 
 * @par Description:
 * 反向遍历链表获取数据
 * 
 * @param item      游标变量
 * @param list      链表
 * @param member    数据成员指针
 * @param element   数据成员名称
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT_REVERSE(item, list, member, element)  \
    for (item = list[JH_STATIC_LIST_USE_HEAD].prev, member = &(list[item].element); \
         (item) != (JH_STATIC_LIST_USE_HEAD);                                       \
         item = list[item].prev, member = &(list[item].element))

/**
 * 
 * @par Description:
 * 安全的遍历链表获取数据，可以在遍历中删除结点
 * 
 * @param item      游标变量
 * @param nextitem  游标变量
 * @param list      链表
 * @param member    数据成员指针
 * @param element   数据成员名称
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT_SAFE(item, nextitem, list, member, element)                       \
    for (item = list[JH_STATIC_LIST_USE_HEAD].next, nextitem = list[item].next, member = &(list[item].element); \
         (item) != (JH_STATIC_LIST_USE_HEAD);                                                                   \
         item = nextitem, nextitem = list[item].next, member = &(list[item].element))

/**
 * 
 * @par Description:
 * 安全的反向遍历链表获取数据，可以在遍历中删除结点
 * 
 * @param item      游标变量
 * @param previtem  游标变量
 * @param list      链表
 * @param member    用于保存数据成员的指针
 * @param element   数据成员名称
 * 
 * @retval None.
 * 
 */
#define JH_STATIC_LIST_FOR_EACH_ENTRY_ELEMENT_SAFE_REVERSE(item, previtem, list, member, element)               \
    for (item = list[JH_STATIC_LIST_USE_HEAD].prev, previtem = list[item].prev, member = &(list[item].element); \
         (item) != (JH_STATIC_LIST_USE_HEAD);                                                                   \
         item = previtem, previtem = list[item].prev, member = &(list[item].element))

/**
 * 
 * @par Description:
 * 查看链表头的数据
 * 
 * @attention
 * None.
 * 
 * @param list      链表
 * @param type      数据成员类型
 * @param element   数据成员名称
 * 
 * @retval 数据成员地址.
 * 
 */
#define JH_STATIC_LIST_PEEK_HEAD_TYPE(list, type, element) ({               \
    type *__t;                                                              \
    if (list[JH_STATIC_LIST_USE_HEAD].next == JH_STATIC_LIST_USE_HEAD) {    \
        __t = NULL;                                                         \
    } else {                                                                \
        __t = &(list[list[JH_STATIC_LIST_USE_HEAD].next].element);          \
    }                                                                       \
    __t;                                                                    \
})

/**
 * 
 * @par Description:
 * 查看链表尾的数据
 * 
 * @attention
 * None.
 * 
 * @param list      链表
 * @param type      数据成员类型
 * @param element   数据成员名称
 * 
 * @retval 数据成员地址.
 * 
 */
#define JH_STATIC_LIST_PEEK_TAIL_TYPE(list, type, element) ({               \
    type *__t;                                                              \
    if (list[JH_STATIC_LIST_USE_HEAD].prev == JH_STATIC_LIST_USE_HEAD) {    \
        __t = NULL;                                                         \
    } else {                                                                \
        __t = &(list[list[JH_STATIC_LIST_USE_HEAD].prev].element);          \
    }                                                                       \
    __t;                                                                    \
})

/**
 * 
 * @par Description:
 * 获取链表头的数据，并删除释放结点
 * 
 * @attention
 * 存在安全性问题，返回数据成员地址的时候，已将结点删除并释放了
 * 如果只用于删除并释放结点则无此问题
 * 
 * @param list      链表
 * @param type      数据成员类型
 * @param element   数据成员名称
 * 
 * @retval 数据成员地址.
 * 
 */
#define JH_STATIC_LIST_REMOVE_HEAD_TYPE(list, type, element) ({                     \
    type *__t;                                                                      \
    if (list[JH_STATIC_LIST_USE_HEAD].next == JH_STATIC_LIST_USE_HEAD) {            \
        __t = NULL;                                                                 \
    } else {                                                                        \
        __t = &(list[list[JH_STATIC_LIST_USE_HEAD].next].element);                  \
        jh_static_list_delete_and_free(list, list[JH_STATIC_LIST_USE_HEAD].next);   \
    }                                                                               \
    __t;                                                                            \
})

/**
 * 
 * @par Description:
 * 获取链表尾的数据，并删除释放结点
 * 
 * @attention
 * 存在安全性问题，返回数据成员地址的时候，已将结点删除并释放了
 * 如果只用于删除并释放结点则无此问题
 * 
 * @param list      链表
 * @param type      数据成员类型
 * @param element   数据成员名称
 * 
 * @retval 数据成员地址.
 * 
 */
#define JH_STATIC_LIST_REMOVE_TAIL_TYPE(list, type, element) ({                     \
    type *__t;                                                                      \
    if (list[JH_STATIC_LIST_USE_HEAD].prev == JH_STATIC_LIST_USE_HEAD) {            \
        __t = NULL;                                                                 \
    } else {                                                                        \
        __t = &(list[list[JH_STATIC_LIST_USE_HEAD].prev].element);                  \
        jh_static_list_delete_and_free(list, list[JH_STATIC_LIST_USE_HEAD].prev);   \
    }                                                                               \
    __t;                                                                            \
})

/**
 * 
 * @par Description:
 * 获取链表头的数据，并删除结点
 * 
 * @attention
 * None.
 * 
 * @param list      链表
 * @param element   数据成员名称
 * @param data      用于保存数据的变量
 * 
 * @retval TRUE     成功.
 * @retval FALSE    无数据.
 * 
 */
#define JH_STATIC_LIST_REMOVE_HEAD_TYPE_SAFE(list, element, data) ({                \
    int __t;                                                                        \
    if (list[JH_STATIC_LIST_USE_HEAD].next == JH_STATIC_LIST_USE_HEAD) {            \
        __t = 0;                                                                    \
    } else {                                                                        \
        memcpy(&data, &(list[list[JH_STATIC_LIST_USE_HEAD].next].element),          \
                sizeof(list[list[JH_STATIC_LIST_USE_HEAD].next].element));          \
        jh_static_list_delete_and_free(list, list[JH_STATIC_LIST_USE_HEAD].next);   \
        __t = 1;                                                                    \
    }                                                                               \
    __t;                                                                            \
})

/**
 * 
 * @par Description:
 * 获取链表尾的数据，并删除结点
 * 
 * @attention
 * None.
 * 
 * @param list      链表
 * @param element   数据成员名称
 * @param data      用于保存数据的变量
 * 
 * @retval TRUE     成功.
 * @retval FALSE    无数据.
 * 
 */
#define JH_STATIC_LIST_REMOVE_TAIL_TYPE_SAFE(list, element, data) ({                \
    int __t;                                                                        \
    if (list[JH_STATIC_LIST_USE_HEAD].prev == JH_STATIC_LIST_USE_HEAD) {            \
        __t = 0;                                                                    \
    } else {                                                                        \
        memcpy(&data, &(list[list[JH_STATIC_LIST_USE_HEAD].prev].element),          \
                sizeof(list[list[JH_STATIC_LIST_USE_HEAD].prev].element));          \
        jh_static_list_delete_and_free(list, list[JH_STATIC_LIST_USE_HEAD].prev);   \
        __t = 1;                                                                    \
    }                                                                               \
    __t;                                                                            \
})

/**
 * 
 * @par Description:
 * 将数据添加到链表头中，自动申请
 * 
 * @attention
 * None.
 * 
 * @param list      链表
 * @param element   数据成员名称
 * @param data      用于保存数据的变量
 * 
 * @retval __cursor 游标.
 * 
 */
#define JH_STATIC_LIST_ADD_HEAD_TYPE(list, element, data) ({                        \
    uint32_t __cursor = jh_static_list_malloc(list);                                \
    if(__cursor) {                                                                  \
        memcpy(&(list[__cursor].element), &data, sizeof(list[__cursor].element));   \
        jh_static_list_head_insert(list, __cursor);                                 \
    }                                                                               \
    __cursor;                                                                       \
})

/**
 * 
 * @par Description:
 * 将数据添加到链表尾中，自动申请
 * 
 * @attention
 * None.
 * 
 * @param list      链表
 * @param element   数据成员名称
 * @param data      用于保存数据的变量
 * 
 * @retval __cursor 游标.
 * 
 */
#define JH_STATIC_LIST_ADD_TAIL_TYPE(list, element, data) ({                        \
    uint32_t __cursor = jh_static_list_malloc(list);                                \
    if(__cursor) {                                                                  \
        memcpy(&(list[__cursor].element), &data, sizeof(list[__cursor].element));   \
        jh_static_list_tail_insert(list, __cursor);                                 \
    }                                                                               \
    __cursor;                                                                       \
})

/**
 * 
 * @par Description:
 * 将数据添加到链表中，自动申请
 * 
 * @attention
 * None.
 * 
 * @param list      链表
 * @param target    要添加在哪个游标位置之后
 * @param element   数据成员名称
 * @param data      用于保存数据的变量
 * 
 * @retval __cursor 游标.
 * 
 */
#define JH_STATIC_LIST_ADD_TARGET_TYPE(list, target, element, data) ({              \
    uint32_t __cursor = jh_static_list_malloc(list);                                \
    if(__cursor) {                                                                  \
        memcpy(&(list[__cursor].element), &data, sizeof(list[__cursor].element));   \
        jh_static_list_add(list, target, __cursor);                                 \
    }                                                                               \
    __cursor;                                                                       \
})

#endif